%{
#ifndef _PARSE_Y_
#define _PARSE_Y_
    #include <stdio.h>
    #include <list>
    #include <string>
    #include "../verisim/operand.h"
    #include "../verisim/line.h"
#define YYPRINT(file, type, value) fprintf(file, "%d", value);

    struct OPS{
        OperandType type;
        int value;
        string name;
    };

    struct LINES{
        LineType type;
        LinePeriodicity periodical;
        int perion;
        string dst_name;
    };

    class ast_node
    {
        list<ast_node*> nodes;
        list<LINES> lines;
        list<OPS> opers;
    };

    list<OPS>    totop;
    list<LINES>         totlin;

    list<pair<string,string> > name_map;

    extern int yylineno;
    extern int yylex();
    void yyerror(char *s) 
    {
        fprintf (stderr, "%s\n", s);
    }
#endif //_PARSE_Y_
%}

%union{
    char* str;
    struct {
        long value;
        long bits;
    }mask;
}

%token ALWAYS 
%token EQUAL
%token POSEDGE
%token NEGEDGE
%token OR
%token BEG
%token END
%token AND
%token IF
%token ELSE
%token INIT
%token AT
%token ID
%token NUM
%token MODULE
%token INPUT
%token OUTPUT
%token REG
%token WIRE
%token INTEGER
%token TIME
%token BIT_MASK;
%token OCT_MASK;
%token DEC_MASK;
%token HEX_MASK;


%left OR
%left AND

%type<str> ID 
%type<mask> BIT_MASK OCT_MASK DEC_MASK HEX_MASK
%type<int> VAL NUM VAL_DEC EXPR_CALC

%%

PROGRAM: OPS ;

OPS: INIT_BLOCK | VAL_DEC | MODULE_INIT | OP_BLOCK
| OPS OPS

OP_CALC: ID EQUAL EXPR_CALC
|   TIME OP_CALC

OP_BLOCK: OP_CALC ';'
| '{' OP_BLOCK '}'
|   IF '(' EXPR ')' OP_BLOCK   {; }
|   IF '(' EXPR ')' OP_BLOCK ELSE OP_BLOCK {;}
|   OP_TREE

OP_TREE: ALWAYS AT '(' POSNEG_EXPR ')' OP_BLOCK {;}
|   ALWAYS INIT_VAL {;}

POSNEG_EXPR: POSEDGE ID
| POSNEG_EXPR OR POSNEG_EXPR
| POSNEG_EXPR AND POSNEG_EXPR ; 

EXPR: EXPR_CALC {$$ = $1;}
|   '!' EXPR_CALC {$$ = !$1;}
|   EXPR '>' EXPR_CALC {$$ = ($1>$2);}
|   EXPR '<' EXPR_CALC {$$ = ($1<$2);}
|   EXPR '=' EXPR_CALC {$$ = ($1==$2);}

EXPR_CALC: VAL
|   TERM '+' VAL { $$ = $1 + $2;}
|   TERM '-' VAL { $$ = $1 - $2;}

TERM: VAL
|   TERM '*' VAL {$$ = $1 * $2;}
|   TERM '/' VAL {$$ = $1 / $2;}

VAL: MASK {$$=$1.mask.value;}
|   '~' VAL {$$=0; OPS* ops = new OPS(OPERAND_ASSIGN, MAX32, "="); totop.push_back(ops);}
|   '(' EXPR_CALC ')'
|   ID {$$=0;}

VAL_DEC: REG ID ';' {OPS* ops = new OPS(OPERAND_REG, 0, $2); totop.push_back(ops);printf("%s\n",$2);}
| WIRE '[' NUM ':' NUM ']' ID ';' {OPS* ops = new OPS(OPERAND_REG, 0, $4); totop.push_back(ops);}

INIT_BLOCK: INIT BEG INIT_VAL END ;

INIT_VAL: ID '=' VAL ';' {OPS* ops = new OPS(OPERAND_ASSIGN, MAX32, "="); totop.push_back(ops);}
| TIME_DEF
| INIT_VAL INIT_VAL

TIME_DEF: TIME ID '=' VAL ';' {OPS* ops = new OPS(OPERAND_ASSIGN, MAX32, "="); totop.push_back(ops) }

MODULE_INIT: MODULE ID '(' PARAMS ')' ';';

PARAMS: INPUT ID 
| OUTPUT ID
| INPUT REG '[' NUM ':' NUM ']' ID
| OUTPUT REG '[' NUM ':' NUM ']' ID
| PARAMS ',' PARAMS ;

MASK: BIT_MASK
| OCT_MASK
| DEC_MASK
| HEX_MASK ;

%%
int main () 
{
    int out = yyparse();
    if (out!=0) printf("SYNTAX ERROR\n");
    for (list<OPS>::iterator it = totop.begin(); it!=totop.end(); it++)
    {
        printf("name %s\n", it.name);
    }
    return out;
}
